<template>
	<view class="container">
		<!-- 顶部信息 -->
		<view class="header">
			<view class="left-info">
				<image src="/static/logo.png" class="logo" @tap="onCardClick()" />
				<view class="distance-info">
					<text style="margin-right:30rpx;">当前里程 <text
							class="highlight">{{ currentCamper.currentMileage }}</text>km</text>
					<text>总里程 <text class="highlight">{{ currentCamper.totalMileage }}</text>km</text>
				</view>
				<view class="divider-line"></view>
				<view class="idle-shutdown-tip">
					<view class="tip-left">
						<text>车辆空闲 <text class="countdown">{{ formattedCountdown }}</text> 后将自动关机</text>
					</view>
				</view>
			</view>
			<view class="right-info">
				<view class="model-wrap">
					<picker mode="selector" :range="modelOptions" @change="onModelChange">
						<view class="model">
							型号: {{ currentModel || '请选择' }}
							<image src="@/static/icon-model.png" class="model-icon" />
						</view>
					</picker>
				</view>
				<view class="wifi" :style="{ color: currentConnectionStatus === 0 ? 'red' : '#0052d9' }"
					@tap="handleWifiClick">
					<image src="@/static/icon-wifi.png" class="wifi-icon" />
					<text>{{ currentConnectionStatus === 0 ? '车辆未连接' : '车辆已连接' }}</text>
				</view>
				<view class="rssi">WiFi信号强度: {{ currentCamper.rssi || '无' }}</view>
			</view>
		</view>

		<!-- 状态卡片 -->
		<view class="status-card">
			<image src="@/static/cart.png" class="cart-img" />
			<view class="status-row">
				<view class="status-item">
					<image src="@/static/icon-power.png" class="icon" />
					<text class="green">{{ currentCamper.batteryPercent }}%</text>
				</view>
				<view class="status-item">
					<image src="@/static/icon-speed.png" class="icon" />
					<text class="red">{{ currentCamper.speed }}KM/H</text>
				</view>
				<view class="status-item">
					<image src="@/static/icon-current.png" class="icon" />
					<text>{{ currentCamper.batteryCapacity }}mA</text>
				</view>
			</view>
		</view>

		<!-- 控制按钮 -->
		<view class="control-section">

			<!-- 第一行：5个按钮 -->
			<!-- 模式按钮 -->
			<view class="row row-top">
				<!-- 模式按钮区域 -->
				<view class="ctrl-btn small" :class="{ active: currentCamper.modeA === 1 }" @tap="toggleMode(1)">
					<image :src="getIcon('ctrl-high', currentCamper.modeA === 1)" class="ctrl-icon" />
					<text>高速</text>
				</view>
				<view class="ctrl-btn small" :class="{ active: currentCamper.modeA === 2 }" @tap="toggleMode(2)">
					<image :src="getIcon('ctrl-light', currentCamper.modeA === 2)" class="ctrl-icon" />
					<text>轻载</text>
				</view>
				<view class="ctrl-btn small" :class="{ active: currentCamper.modeA === 4 }" @tap="toggleMode(4)">
					<image :src="getIcon('ctrl-outdoor', currentCamper.modeA === 4)" class="ctrl-icon" />
					<text>户外</text>
				</view>

				<view class="ctrl-btn small" :class="{ active: currentCamper.modeB === 3 }" @tap="toggleMode(3)">
					<image :src="getIcon('ctrl-cruise', currentCamper.modeB === 3)" class="ctrl-icon" />
					<text>巡航</text>
				</view>
				<view class="ctrl-btn small" :class="{ active: currentCamper.modeB === 5 }" @tap="toggleMode(5)">
					<image :src="getIcon('ctrl-boost', currentCamper.modeB === 5)" class="ctrl-icon" />
					<text>助力</text>
				</view>
			</view>

			<!-- 第二行：左右各2个 + 中间摇杆 -->
			<view class="row row-bottom">
				<!-- 左侧 -->
				<view class="side-column">
					<view class="ctrl-btn small" :style="{ color: currentCamper.brakeStatus ? '#2a68ff' : '' }"
						@tap="toggleStatus('brakeStatus')">
						<image :src="getIcon('ctrl-brake', currentCamper.brakeStatus)" class="ctrl-icon" />
						<text>刹车</text>
					</view>
					<view class="ctrl-btn small" :style="{ color: currentCamper.routerStatus ? '#2a68ff' : '' }"
						@tap="showLYQspot = true">
						<image :src="getIcon('ctrl-wifi', currentCamper.routerStatus)" class="ctrl-icon" />
						<text>路由器</text>
					</view>
				</view>

				<!-- 修改后的摇杆结构 -->
				<!-- 增加最外层灰色环视图 -->
				<view class="joystick-ring">
					<view class="joystick-container" @touchstart="onJoystickStart" @touchmove="onJoystickMove"
						@touchend="onJoystickEnd" @touchcancel="onJoystickCancel">
						<view class="joystick-track">
							<view class="joystick-thumb" :style="thumbPosition"></view>
						</view>
					</view>
				</view>

				<!-- 右侧 -->
				<view class="side-column">
					<view class="ctrl-btn small" :style="{ color: currentCamper.lightStatus ? '#2a68ff' : '' }"
						@tap="toggleStatus('lightStatus')">
						<image :src="getIcon('ctrl-lightbulb', currentCamper.lightStatus)" class="ctrl-icon" />
						<text>灯光</text>
					</view>
					<!-- <view class="ctrl-btn small" @tap="toggleStatus('hornStatus')"
						:style="{ color: currentCamper.hornStatus ? '#2a68ff' : '' }">
						<image :src="getIcon('ctrl-horn', currentCamper.hornStatus)" class="ctrl-icon" />
						<text>喇叭</text>
					</view> -->
					<view class="ctrl-btn small" @touchstart="sendHorn(true)" @touchend="sendHorn(false)"
						:style="{ color: currentCamper.hornStatus ? '#2a68ff' : '' }">
						<image :src="getIcon('ctrl-horn', currentCamper.hornStatus)" class="ctrl-icon" />
						<text>喇叭</text>
					</view>
				</view>
			</view>
		</view>

		<!-- 底部功能 -->
		<view class="bottom-row-box">
			<view class="bottom-btn left" :style="{ color: currentCamper.autoFollowStatus ? '#2a68ff' : '' }"
				@tap="toggleStatus('autoFollowStatus')">
				<image :src="getIcon('icon-follow', currentCamper.autoFollowStatus)" class="ctrl-icon" />
				<text>自动跟随</text>
			</view>
			<view class="bottom-btn right" :style="{ color: currentCamper.oneKeyRecallStatus ? '#2a68ff' : '' }"
				@tap="toggleStatus('oneKeyRecallStatus')">
				<image :src="getIcon('icon-back', currentCamper.oneKeyRecallStatus)" class="ctrl-icon" />
				<text>一键召回</text>
			</view>
		</view>
		<!-- 故障代码 -->
		<view class="error-code">
			故障代码：<text style="color: red;">{{ currentCamper.faultDescription }}</text>
		</view>

		<!-- 热点弹窗 -->
		<view v-if="showHotspot" class="modal">
			<view class="modal-content">
				<view class="modal-title">创建手机热点连接设备</view>
				<view class="info">
					<text>WIFI名称：</text>
					<view class="info-box">
						<text>{{ wifiName }}</text>
						<image src="@/static/copy.png" class="copy-icon" @tap="copyText(wifiName)" />
					</view>
				</view>
				<view class="info">
					<text>WIFI密码：</text>
					<view class="info-box">
						<text>{{ wifiPassword }}</text>
						<image src="@/static/copy.png" class="copy-icon" @tap="copyText(wifiPassword)" />
					</view>
				</view>
				<view class="modal-tip">
					如果无法自动创建热点，请将上面热点的信息复制到手机热点设置，手动进行热点创建，设备连接成功后即可开始控制。
				</view>
				<view class="modal-buttons">
					<button class="btn cancel" @tap="showHotspot = false">关闭</button>
					<button class="btn confirm" @tap="createHotspot">创建热点</button>
				</view>
			</view>
		</view>
		<!-- 路由器配置弹窗 -->
		<view v-if="showLYQspot" class="modal">
			<view class="modal-content">
				<view class="modal-title">露营车WiFi配置</view>
				<view class="info">
					<text>WiFi名称：</text>
					<view class="info-box">
						<input class="input" placeholder="请输入WiFi名称" v-model="wifiName"
							placeholder-class="input-placeholder" />
					</view>
				</view>
				<view class="info">
					<text>WiFi密码：</text>
					<view class="info-box">
						<input class="input" placeholder="请输入WiFi密码" v-model="wifiPassword"
							placeholder-class="input-placeholder" />
					</view>
				</view>
				<view class="modal-buttons">
					<button class="btn cancel" @tap="showLYQspot = false">关闭</button>
					<button class="btn confirm" @tap="confirmWifiConfig">确认</button>
				</view>
			</view>
		</view>
		<view v-if="isConnecting" class="loading-overlay">
			<view class="loading-box">
				<view class="spinner"></view>
				<text class="loading-text">等待露营车连接中...</text>
			</view>
		</view>
		<!-- 底部导航 -->
		<view class="tabbar">
			<view class="tab-item" @tap="toHome">
				<image src="@/static/icon-home.png" class="icon-tab" />
				<text>观猎</text>
			</view>
			<view class="tab-item active">
				<image src="@/static/icon-control-active.png" class="icon-tab" />
				<text>控制</text>
			</view>
		</view>

	</view>
</template>

<script>
	const FvvUniWifiHelper = uni.requireNativePlugin("Fvv-UniWifiHelper");
	export default {
		data() {
			return {
				showHotspot: false, //热点弹窗
				showLYQspot: false, //路由器弹窗
				wifiName: '', //wifi名称
				wifiPassword: '', //wifi密码
				selectedCamper: null, // 区别是添加露营车还是点击已有露营车
				shouldCheckWifi: false, // 标志：是否应该开始检测连接
				isConnecting: false, //控制wifi连接中样式
				heartStatus: 0,
				heartbeatInProgress: false,
				// lastSentCommand: null, //旧指令
				topControls: [{
						icon: "@/static/ctrl-high.png",
						label: "高速"
					},
					{
						icon: "@/static/ctrl-light.png",
						label: "轻载"
					},
					{
						icon: "@/static/ctrl-cruise.png",
						label: "巡航"
					},
					{
						icon: "@/static/ctrl-outdoor.png",
						label: "户外"
					},
					{
						icon: "@/static/ctrl-boost.png",
						label: "助力"
					},
				],
				leftControls: [{
						icon: "@/static/ctrl-brake.png",
						label: "刹车"
					},
					{
						icon: "@/static/ctrl-wifi.png",
						label: "路由器"
					},
				],
				rightControls: [{
						icon: "/static/ctrl-lightbulb.png",
						label: "灯光"
					},
					{
						icon: "/static/ctrl-horn.png",
						label: "喇叭"
					},
				],
				camperList: [], //本地露营车数据
				currentModel: '', //当前露营车型号（根据wifi名称匹配）
				currentConnectionStatus: 0, //wifi连接状态
				currentIP: '', // 当前ip
				currentCamper: {
					// 以下属性将从匹配的 camper 中获取
					wifiStatus: 0,
					wifiName: null,
					wifiPassword: null,
					currentMileage: 0,
					totalMileage: 0,
					batteryPercent: 0,
					speed: 0,
					batteryCapacity: 0,
					modeA: 0,
					modeB: 0,
					brakeStatus: false,
					lightStatus: false,
					routerStatus: false,
					hornStatus: false,
					autoFollowStatus: false,
					oneKeyRecallStatus: false,
					faultDescription: '',
					rssi: '无',
				},
				tempControlState: {
					mode: {
						isControlling: false,
						timeout: null
					},
					brakeStatus: {
						isControlling: false,
						timeout: null
					},
					lightStatus: {
						isControlling: false,
						timeout: null
					},
					autoFollowStatus: {
						isControlling: false,
						timeout: null
					},
					oneKeyRecallStatus: {
						isControlling: false,
						timeout: null
					},
				},
				statusCommands: {
					lightStatus: ['FE5406030104', 'FE5406030003'], // 开/关灯光
					brakeStatus: ['FE5406020103', 'FE5406020002'], // 启用/解除刹车
					routerStatus: ['FE5406040105', 'FE5406040004'], // 开/关路由器
					hornStatus: ['FE5406050106', 'FE5406050005'], // 打开/关闭喇叭
					autoFollowStatus: ['FE540609010A', 'FE5406090009'], // 启用/关闭自动跟随
					oneKeyRecallStatus: ['FE54060A010B', 'FE54060A000A'] // 启用/关闭一键召回
				},
				joystick: {
					centerX: 0, // 容器中心X坐标
					centerY: 0, // 容器中心Y坐标
					maxRadius: 0, // 最大移动半径（像素）
					currentX: 0, // 当前X坐标（相对于中心）
					currentY: 0 // 当前Y坐标（相对于中心）
				},
				thumbRadius: 25, // 拇指半径（单位是 px）
				sendInterval: null, // 发送定时器
				heartbeatTimer: null,
				countdown: 600, // 10分钟（单位：秒）
				countdownTimer: null,
				getLANRequestId: 0, // 每次调用自增，用于识别唯一调用
				heartbeatFailCount: 0,
				heartProblem: 0,

			};
		},
		onLoad() {
			// 读取本地连接状态
			const status = uni.getStorageSync('currentConnectionStatus');
			if (status !== '' && status !== null && status !== undefined) {
				this.currentConnectionStatus = status;
			}
			this.loadCampersFromStorage(); //获取本地露营车信息
			this.matchCurrentHotspot(); //获取本地热点信息
			// this.checkHeartbeat();
			// this.checkHeartbeat(); // 初次立即检查一次
			// 启动定时器，每 300ms 检查是否需要发送
			// this.heartbeatTimer = setInterval(() => {
			// 	const shouldSend = getApp().globalData.shouldSendHeartbeat;
			// 	if (shouldSend) {
			// 		this.checkHeartbeat(); // 只在允许时发送
			// 	} else {
			// 		// 可选日志：调试用
			// 		console.log('跳过发送（shouldSendHeartbeat = false）');
			// 	}
			// }, 300);
			// this.getLoadLAN();
			// // 每6秒执行一次 getLoadLAN
			// this.lanTimer = setInterval(() => {
			// 	this.getLoadLAN();
			// }, 6000);
		},
		onUnload() {
			if (this.heartbeatTimer) {
				clearInterval(this.heartbeatTimer);
				this.heartbeatTimer = null;
			}
			if (this.lanTimer) clearInterval(this.lanTimer);
		},
		onHide() {
			if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
			if (this.lanTimer) clearInterval(this.lanTimer);
		},
		mounted() {
			this.startCountdown();
			uni.$on('user-action', this.resetCountdown);
		},
		beforeDestroy() {
			clearInterval(this.countdownTimer);
			uni.$off('user-action', this.resetCountdown);
		},
		onShow() {
			// 先取最新状态
			const status = uni.getStorageSync('currentConnectionStatus');
			if (status !== '' && status !== null && status !== undefined) {
				this.currentConnectionStatus = status;
			}
			if (this.shouldCheckWifi) {
				this.startWifiCheck();
			}
			// 确保只有一个定时器在运行，避免重复定时器
			if (this.heartbeatTimer) {
				clearInterval(this.heartbeatTimer);
				this.heartbeatTimer = null;
			}

			this.heartbeatTimer = setInterval(() => {
				const shouldSend = getApp().globalData.shouldSendHeartbeat;
				if (shouldSend) {
					this.checkHeartbeat();
				} else {
					console.log('跳过心跳发送（shouldSendHeartbeat = false）');
				}
			}, 300);
		},
		// 计算位置
		computed: {
			// currentConnectionStatus() {
			// 		const status = uni.getStorageSync('currentConnectionStatus');
			// 		return status === '' || status === null || status === undefined ? 0 : status;
			// 	},
			thumbPosition() {
				return {
					transform: `translate(calc(-50% + ${this.joystick.currentX}px), calc(-50% + ${this.joystick.currentY}px))`
				}
			},
			modelOptions() {
				const models = this.camperList.map(item => item.model).filter(Boolean);
				return [...new Set(models)];
			},
			formattedCountdown() {
				const minutes = String(Math.floor(this.countdown / 60)).padStart(2, '0');
				const seconds = String(this.countdown % 60).padStart(2, '0');
				return `${minutes}:${seconds}`;
			}
		},
		methods: {
			copyText(text) {
				uni.setClipboardData({
					data: text,
					success: () => {
						uni.showToast({
							title: '复制成功',
							icon: 'none'
						});
					}
				});
			},
			onCardClick() {
				let url = 'https://shop677230g95aq81.1688.com/'
				// 检查是否是安卓平台
				if (uni.getSystemInfoSync().platform === 'android') {
					// 使用 plus.runtime.openURL 打开外部链接
					plus.runtime.openURL(url, () => {
						// console.log('页面打开成功');
					}, () => {
						// console.log('页面打开失败');
					});
				} else {
					// 如果不是安卓平台，可以使用其他方式打开链接
					// console.log('当前平台不支持 plus.runtime.openURL');
					window.location.href = url
				}
			},
			toHome() {
				uni.reLaunch({
					url: '/pages/home/home'
				})
			},
			startCountdown() {
				this.countdownTimer = setInterval(() => {
					if (this.countdown > 0) {
						this.countdown--;
					} else {
						clearInterval(this.countdownTimer);
						uni.showModal({
							title: '提醒',
							content: '车辆已空闲10分钟，即将自动关机',
							showCancel: false
						});
					}
				}, 1000);
			},
			resetCountdown() {
				this.countdown = 600;
			},
			//切换型号
			onModelChange(e) {
				this.currentModel = this.modelOptions[e.detail.value];
				// 重置所有 camper 的 wifiStatus 为 0
				this.camperList = this.camperList.map(camper => {
					// camper.wifiStatus = 0;
					return camper;
				});
				// console.log(this.camperList);
				// 查找当前选择的 camper 并设置 currentCamper
				const matchedCamper = this.camperList.find(camper => camper.model === this.currentModel);
				this.currentConnectionStatus = matchedCamper.wifiStatus;
				uni.setStorageSync('currentConnectionStatus', matchedCamper.wifiStatus); // ← 添加本地存储

				if (matchedCamper) {
					this.currentCamper = {
						wifiName: matchedCamper.wifiName,
						wifiPassword: matchedCamper.wifiPassword,
						currentMileage: matchedCamper.currentMileage || 0,
						totalMileage: matchedCamper.totalMileage || 0,
						batteryPercent: matchedCamper.batteryPercent || 0,
						speed: matchedCamper.speed || 0,
						batteryCapacity: matchedCamper.batteryCapacity || 0,
						modeA: matchedCamper.modeA || 0,
						modeB: matchedCamper.modeB || 0,
						brakeStatus: matchedCamper.brakeStatus || false,
						lightStatus: matchedCamper.lightStatus || false,
						routerStatus: matchedCamper.routerStatus || false,
						hornStatus: matchedCamper.hornStatus || false,
						autoFollowStatus: matchedCamper.autoFollowStatus || false,
						oneKeyRecallStatus: matchedCamper.oneKeyRecallStatus || false
					};
				}
			},
			// 初始化摇杆尺寸
			async initJoystick() {
				const res = await new Promise(resolve => {
					uni.createSelectorQuery().in(this)
						.select('.joystick-track')
						.boundingClientRect(rect => resolve(rect))
						.exec()
				})
				this.joystick = {
					centerX: res.left + res.width / 2,
					centerY: res.top + res.height / 2,
					maxRadius: res.width / 2 - this.thumbRadius, // 动态减去拇指半径
					currentX: 0,
					currentY: 0
				}
			},
			// 触摸开始
			onJoystickStart(e) {
				if (this.heartStatus !== 1) {
					uni.showToast({
						title: '设备正在配对，请稍候再试',
						icon: 'none',
						duration: 2000
					});
					return;
				}
				if (this.currentConnectionStatus !== 1) {
					uni.showToast({
						title: 'wifi未连接，请稍候再试',
						icon: 'none',
						duration: 2000
					});
					return;
				}
				if (e.touches.length > 1) return;
				this.initJoystick();
				this.handleJoystickMove(e.touches[0]);

				if (!this.sendLoopRunning) {
					this.sendLoopRunning = true;
					this.joystickCommandLoop(); // 启动异步指令循环
				}
			},
			async joystickCommandLoop() {
				// this.lastSentCommand = null;
				while (this.sendLoopRunning) {
					const {
						currentX,
						currentY
					} = this.joystick;
					// ✅ 如果摇杆归零，就停止发送，退出循环
					// if (currentX === 0 && currentY === 0) {
					// 	console.log("摇杆归零，停止指令循环");
					// 	this.sendLoopRunning = false;
					// 	const command = 'FE54060B000B';
					// 	this.sendCommand(command);
					// 	break;
					// }
					const directions = this.calculateDirections(currentX, currentY);
					const command = this.generateCommand(directions);

					// ✅ 如果和上次一样，就不再发
					// if (command === this.lastSentCommand) {
					// 	await new Promise(resolve => setTimeout(resolve, 50));
					// 	continue;
					// }

					// this.lastSentCommand = command;

					try {
						await this.sendCommand(command); // ✅ 等待指令发送完成
					} catch (err) {
						console.warn('指令发送失败（忽略）:', err);
					}

					// 延迟 50ms 再继续下一次
					await new Promise(resolve => setTimeout(resolve, 50));
				}
			},
			// async onJoystickStart(e) {
			// 	// 只允许单指控制
			// 	if (e.touches.length > 1) return
			// 	this.initJoystick()
			// 	this.handleJoystickMove(e.touches[0])
			// 	// 启动定时发送
			// 	if (!this.sendInterval) {
			// 		this.sendInterval = setInterval(() => {
			// 			const {
			// 				currentX,
			// 				currentY
			// 			} = this.joystick
			// 			const directions = this.calculateDirections(currentX, currentY)
			// 			const command = this.generateCommand(directions)
			// 			// this.sendCommand(command) // 这里执行你的指令发送逻辑
			// 			try {
			// 				await this.sendCommand(command); // 等待发送完成再继续
			// 			} catch (err) {
			// 				console.warn('指令发送失败（忽略）:', err);
			// 			}
			// 			// 等待 50ms 再发下一条
			// 			await new Promise(resolve => setTimeout(resolve, 50));
			// 		}, 50)
			// 	}
			// },
			// 触摸移动
			onJoystickMove(e) {
				// if (this.heartStatus !== 1) {
				//         uni.showToast({
				//             title: '设备正在配对，请稍候再试',
				//             icon: 'none',
				//             duration: 2000
				//         });
				//         return;
				//     }
				if (this.heartStatus !== 1) return;

				// 如果wifi未连接，禁止移动
				if (this.currentConnectionStatus !== 1) return;
				if (e.touches.length > 1) return
				if (!e.touches.length) return
				this.handleJoystickMove(e.touches[0])
			},
			// 被系统打断的触摸（如通知栏、电话等）
			onJoystickCancel() {
				this.clearJoystick()
			},
			// 处理移动逻辑
			handleJoystickMove(touch) {
				// 计算相对中心点的偏移量
				const deltaX = touch.clientX - this.joystick.centerX
				const deltaY = touch.clientY - this.joystick.centerY
				// 限制在圆形范围内
				const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
				const ratio = distance > this.joystick.maxRadius ?
					this.joystick.maxRadius / distance : 1
				this.joystick.currentX = deltaX * ratio
				this.joystick.currentY = deltaY * ratio
			},
			// 触摸结束
			onJoystickEnd() {
				this.clearJoystick()
			},
			// 封装摇杆复位和定时器清除逻辑
			clearJoystick() {
				this.sendLoopRunning = false; // 停止循环
				clearInterval(this.sendInterval)
				this.sendInterval = null
				this.joystick.currentX = 0
				this.joystick.currentY = 0
				this.lastCommand = null // 如果你有这个字段记得也重置

				// ✅ 发送归位指令，延迟 50ms
				const command = 'FE54060B000B';
				setTimeout(() => {
					// this.sendCommand(command);
					this.sendCommandWithRetry(command, 10, 300);
				}, 50);
			},

			// 计算四个方向值（0 ~ 255）
			calculateDirections(x, y) {
				const max = this.joystick.maxRadius
				const scale = v => {
					const val = Math.floor((v / max) * 255)
					return val <= 0 ? 0 : Math.min(255, val)
				}
				return {
					up: y < 0 ? scale(-y) : 0,
					down: y > 0 ? scale(y) : 0,
					left: x < 0 ? scale(-x) : 0,
					right: x > 0 ? scale(x) : 0
				}
			},
			// 生成移动速度命令（上/下/左/右是2字节十六进制，范围0~255）
			generateCommand({
				up,
				down,
				left,
				right
			}) {
				// 将数值限制为 0~255，负数或0 = 0，最大255
				const toHex = (v) => {
					const val = Math.max(0, Math.min(255, Math.round(v)))
					return val === 0 ? '00' : val.toString(16).padStart(2, '0')
				}
				const upHex = toHex(up)
				const downHex = toHex(down)
				const leftHex = toHex(left)
				const rightHex = toHex(right)
				// 校验和 = 固定值 06（十进制）+ 4个方向的十进制总和
				const sum = 0x06 +
					parseInt(upHex, 16) +
					parseInt(downHex, 16) +
					parseInt(leftHex, 16) +
					parseInt(rightHex, 16)
				const checksum = (sum & 0xFF).toString(16).padStart(2, '0').toUpperCase()
				const command = `FE540906${upHex}${downHex}${leftHex}${rightHex}${checksum}`.toUpperCase();

				// console.log('🕹️ 简化指令:', command)
				return command
			},
			calcChecksum(hexString) {
				let sum = 0
				for (let i = 0; i < hexString.length; i += 2) {
					sum += parseInt(hexString.substr(i, 2), 16)
				}
				return (sum & 0xff).toString(16).padStart(2, '0').toUpperCase()
			},
			//模式控制
			toggleMode(modeIndex) {
				// 控制期间锁定
				this.tempControlState.mode.isControlling = true;
				// 锁定 2 秒，防止覆盖
				clearTimeout(this.tempControlState.mode.timeout);
				this.tempControlState.mode.timeout = setTimeout(() => {
					this.tempControlState.mode.isControlling = false;
				}, 2000);
				const modeCommands = {
					1: 'FE5406010102', // 高速
					2: 'FE5406010203', // 轻载
					3: 'FE5406010506', // 巡航
					4: 'FE5406010304', // 户外
					5: 'FE5406010405' // 助力
				};
				const exitCommands = {
					3: 'FE5406010607', // 巡航退出
					5: 'FE5406010708' // 助力退出
				};

				const groupA = [1, 2, 4];
				const groupB = [3, 5];

				// 判断属于哪组
				let group = groupA.includes(modeIndex) ? 'A' : groupB.includes(modeIndex) ? 'B' : null;
				if (!group) {
					console.warn('无效模式:', modeIndex);
					return;
				}
				// 获取当前模式
				let current = group === 'A' ? this.currentCamper.modeA : this.currentCamper.modeB;
				// 如果是 B 组，且重复点击当前模式，发送退出指令
				if (group === 'B' && current === modeIndex) {
					const exitCommand = exitCommands[modeIndex];
					if (exitCommand) {
						// console.log("exitCommand:" + exitCommand);
						this.sendCommand(exitCommand)
							.then(() => {
								this.currentCamper.modeB = 0;
							})
							.catch(() => {
								uni.showToast({
									title: '退出模式失败',
									icon: 'none'
								});
							});
					}
					return;
				}

				const commandHex = modeCommands[modeIndex];
				this.sendCommand(commandHex)
					.then(() => {
						// 更新模式
						if (group === 'A') {
							this.currentCamper.modeA = modeIndex;
						} else {
							this.currentCamper.modeB = modeIndex;
						}
					})
					.catch(() => {
						uni.showToast({
							title: '模式切换失败',
							icon: 'none'
						});
					});
			},
			//喇叭状态控制
			sendHorn(pressing) {
				// 获取指令对：开启/关闭
				const commandPair = this.statusCommands.hornStatus;
				if (!commandPair) return;

				// 根据按压状态选择要发送的指令
				const commandToSend = pressing ? commandPair[0] : commandPair[1];

				this.sendCommand(commandToSend)
					.then(() => {
						// 同步状态用于视图更新
						this.currentCamper.hornStatus = pressing;
					})
					.catch(() => {
						uni.showToast({
							title: '喇叭操作失败',
							icon: 'none'
						});
					});
			},
			//状态控制
			toggleStatus(key) {
				const currentValue = this.currentCamper[key];
				const commandPair = this.statusCommands[key];
				if (!commandPair) return;

				// 如果该状态正在控制中，阻止重复点击
				// if (this.tempControlState[key]?.isControlling) return;
				// 如果已是目标状态，跳过
				const commandToSend = currentValue ? commandPair[1] : commandPair[0];

				// 开始控制：设置锁定标志
				if (!this.tempControlState[key]) {
					this.$set(this.tempControlState, key, {
						isControlling: true,
						timeout: null
					});
				} else {
					this.tempControlState[key].isControlling = true;
					clearTimeout(this.tempControlState[key].timeout);
				}
				this.sendCommand(commandToSend)
					.then(() => {
						this.currentCamper[key] = !currentValue;

						// 控制完成后，延迟 2 秒后释放锁定，允许覆盖
						this.tempControlState[key].timeout = setTimeout(() => {
							this.tempControlState[key].isControlling = false;
						}, 2000);
					})
					.catch(() => {
						uni.showToast({
							title: '信号较弱，请靠近露营车后重试',
							icon: 'none'
						});
					});
			},
			//获取本地露营车信息
			loadCampersFromStorage() {
				const storedCampers = uni.getStorageSync('campers') || [];
				this.camperList = storedCampers;

				// console.log('读取本地露营车信息:', this.camperList);
				const getcurrentIP = uni.getStorageSync('campers') || [];
				this.currentIP = getcurrentIP;
				// console.log('当前ip:', this.currentIP);
			},
			//获取本地热点信息
			matchCurrentHotspot() {
				const current = uni.getStorageSync('currentHotspot');
				// console.log('当前wifi信息:', current.wifiName);
				if (current && current.wifiName) {
					const match = this.camperList.find(item => item.wifiName === current.wifiName);
					if (match) {
						// console.log('当前match信息:', match);
						this.currentModel = match.model;
						// this.currentConnectionStatus = match.wifiStatus;
						// uni.setStorageSync('currentConnectionStatus', match.wifiStatus); // ← 添加本地存储
						// 设置整台车状态
						this.currentCamper = {
							...match
						};
					}
				}
			},
			//wifi未连接发送获取区域网设备
			handleWifiClick() {
				if (this.currentConnectionStatus === 1) {
					// 已连接，弹出确认提示
					uni.showModal({
						title: '提示',
						content: '当前已连接WiFi，确定要断开连接吗？',
						confirmText: '断开',
						cancelText: '取消',
						success: (res) => {
							if (res.confirm) {
								getApp().globalData.shouldSendHeartbeat = false; //不在发送
								const commandHex = 'FE5406040004';
								this.sendCommand(commandHex)
									.then(() => {
										// 清除本地连接信息
										// uni.removeStorageSync('currentIP'); // 如果你是用这个 key 存的
										this.currentConnectionStatus = 0;
										uni.setStorageSync('currentConnectionStatus', 0); // ← 添加本地存储
										uni.showToast({
											title: 'WiFi已断开',
											icon: 'success'
										});
									})
									.catch(() => {
										uni.showToast({
											title: '断开失败',
											icon: 'none'
										});
									});
							}
						}
					});
					return;
				}
				this.showHotspot = true;
				this.wifiName = this.currentCamper.wifiName;
				this.wifiPassword = this.currentCamper.wifiPassword;
			},
			// 十六进制字符串转字节数组
			hexStringToBytes(hexString) {
				hexString = hexString.replace(/[^0-9A-Fa-f]/g, ''); // 去除非十六进制字符
				const bytes = [];
				for (let i = 0; i < hexString.length; i += 2) {
					bytes.push(parseInt(hexString.substr(i, 2), 16));
				}
				return bytes;
			},
			// 将字节数组转换为浮动点数
			hexToFloat(hexString) {
				const bytes = this.hexStringToBytes(hexString);

				const buffer = new ArrayBuffer(4);
				const view = new DataView(buffer);

				for (let i = 0; i < bytes.length; i++) {
					view.setUint8(i, bytes[i]);
				}

				const floatVal = view.getFloat32(0, true);
				return Math.round(floatVal * 100) / 100; // 保留两位小数，返回数字
			},
			//检查心跳
			checkHeartbeat() {
				const currentIP = this.getCurrentIP();
				if (!currentIP) {
					this.setCamperDisconnected();
					return;
				}
				uni.request({
					url: `http://${currentIP}/heartbeat`,
					method: 'GET',
					timeout: 3000,
					success: (res) => {
						// console.log('心跳成功:', res);
						this.heartbeatFailCount = 0;
						this.currentConnectionStatus = 1;
						uni.setStorageSync('currentConnectionStatus', 1);

						// 假设返回是 hex 字符串：例如 FE551100310032003300340035001A011A
						const hexStr = res.data?.toUpperCase?.().replace(/\s+/g, '');
						// const hexStr = 'FE551700006400C800218A99CD41CDCC834201002B010000011A';
						// const hexStr = 'FE5517006400C80033009A99CD41CDCC834201001A0101010158';
						// 模拟心跳数据列表
						// const heartbeatSamples = [
						// 	'FE551700006400C800218A99CD41CDCC834201002B010000011A',
						// 	'FE551700006500C500218A99CD41CDCC834200001A030101001A',
						// 	'FE551700006500C400219A99CD41CDCC834201001B020201011A',
						// 	'FE551700006700C200219C99CD41CDCC834200002A040300001A'
						// ];
						// 随机选择一个心跳数据
						// const hexStr = heartbeatSamples[Math.floor(Math.random() * heartbeatSamples.length)];
						// this.heartStatus = 1;
						if (!hexStr || !hexStr.startsWith('FE55')) {
							console.warn('心跳数据格式不正确');
							// this.currentConnectionStatus = 0;
							// uni.setStorageSync('currentConnectionStatus', 0); // ← 添加本地存储
							return;
						}

						// 截取帧体部分（不包含FE55和长度码和指令码，共前8位）
						const body = hexStr.slice(8);

						if (body.length < 26) {
							console.warn('心跳数据长度不足');
							return;
						}

						this.heartStatus = 1;

						const batteryPercent = parseInt(body.slice(0, 4), 16) || 0; // 电压，十六进制转十进制
						const batteryCapacity = parseInt(body.slice(4, 8), 16) || 0; // 电流，十六进制转十进制
						const speed = parseInt(body.slice(8, 12), 16) || 0; // 速度，十六进制转十进制
						// currentMileage 和 totalMileage 转换为浮动点数

						const currentMileageHex = body.slice(12, 20); // 获取 currentMileage 十六进制字符串
						const totalMileageHex = body.slice(20, 28); // 获取 totalMileage 十六进制字符串
						const currentMileage = this.hexToFloat(currentMileageHex); // 转换为浮动点数
						const totalMileage = this.hexToFloat(totalMileageHex); // 转换为浮动点数

						const brakeHex = body.slice(28, 30) || '00'; //刹车
						const lightHex = body.slice(30, 32) || '00'; //灯光

						const modeHex = body.slice(32, 34) || '00'; //模式
						const modeAValue = modeHex[0].replace(/^0+/, '') || '0';
						const modeBValue = modeHex[1].replace(/^0+/, '') || '0';

						const faultHex = body.slice(34, 36) || '00';
						const faultCodeMap = {
							'01': '主板温度高',
							'02': '电池电量低',
							'03': '左电机故障',
							'04': '右电机故障',
							'05': '遥控信号未接入',
							'06': '空闲关机'
						};
						let faultDescription = '';
						if (faultHex !== '00' && faultCodeMap[faultHex]) {
							faultDescription = `${faultCodeMap[faultHex]}`;
						}

						// const rssiHex = body.slice(36, 38) || '00';//RSSI信号强度
						// const rssi = parseInt(rssiHex, 16) || 0;
						// this.currentCamper.rssi = rssi;
						// uni.setStorageSync('camperRSSI', rssi);

						const rssiLevel = parseInt(body.slice(36, 38), 16) || 0;
						const rssiMap = ['极强', '较强', '较弱', '极弱'];
						const rssiDescription = rssiMap[rssiLevel] || '无';

						this.currentCamper.rssi = rssiDescription;
						uni.setStorageSync('camperRSSI', rssiLevel);

						const autoFollowHex = body.slice(38, 40) || '00'; //自动跟谁
						const oneKeyRecallHex = body.slice(40, 42) || '00'; //一件召回fff
						// autoFollowStatus: false,
						// oneKeyRecallStatus: false,

						// console.log("body:", body);
						// console.log("batteryPercent:", batteryPercent);
						// console.log("batteryCapacity:", batteryCapacity);
						// console.log("speed:", speed);
						// console.log("currentMileageHex:", currentMileageHex);
						// console.log("totalMileageHex:", totalMileageHex);
						// console.log("currentMileage:", currentMileage);
						// console.log("totalMileage:", totalMileage);

						// console.log("brakeHex:", brakeHex);
						// console.log("lightHex:", lightHex);
						// console.log("autoFollowHex:", autoFollowHex);
						// console.log("oneKeyRecallHex:", oneKeyRecallHex);
						// console.log("modeHex:", modeHex);
						// console.log("modeA:", modeAValue);
						// console.log("modeB:", modeBValue);
						// console.log("rssi:", rssi);

						// 00 表示关，01 表示开
						const brakeStatus = brakeHex === '01' ? 1 : 0;
						const lightStatus = lightHex === '01' ? 1 : 0;
						const autoFollowStatus = autoFollowHex === '01' ? 1 : 0;
						const oneKeyRecallStatus = oneKeyRecallHex === '01' ? 1 : 0;

						let modeA = 0;
						switch (modeAValue.toUpperCase()) {
							case '1':
								modeA = 1; // 高速
								break;
							case '2':
								modeA = 2; // 轻载
								break;
							case '3':
								modeA = 4; // 户外
								break;
							default:
								modeA = 0;
						}

						let modeB = 0;
						switch (modeBValue.toUpperCase()) {
							case 'A':
								modeB = 3; // 巡航
								break;
							case 'B':
								modeB = 5; //助力
								break;
							case 'C':
								modeB = 0; // 关
								break;
							default:
								modeB = 0;
						}
						// 设置到 currentCamper
						// console.log("灯光状态："+this.tempControlState.lightStatus.isControlling)
						if (!this.tempControlState.autoFollowStatus.isControlling) {
							// console.log("autoFollowStatus:" + autoFollowStatus);
							this.currentCamper.autoFollowStatus = autoFollowStatus;
							// console.log("自动跟谁变化了")
						}
						if (!this.tempControlState.oneKeyRecallStatus.isControlling) {
							this.currentCamper.oneKeyRecallStatus = oneKeyRecallStatus;
							// console.log("一键召回变化了")
						}
						if (!this.tempControlState.lightStatus.isControlling) {
							this.currentCamper.lightStatus = lightStatus;
							// console.log("灯光状态变化了")
						}
						// console.log("刹车状态：" + this.tempControlState.brakeStatus.isControlling)
						if (!this.tempControlState.brakeStatus.isControlling) {
							this.currentCamper.brakeStatus = brakeStatus;
							// console.log("刹车状态变化了")
						}
						if (!this.tempControlState.mode.isControlling) {
							this.currentCamper.modeA = modeA;
							this.currentCamper.modeB = modeB;
						}
						// this.currentCamper.brakeStatus = brakeStatus;
						// this.currentCamper.lightStatus = lightStatus;
						// this.currentCamper.modeA = modeA;
						// this.currentCamper.modeB = modeB;
						this.currentCamper.faultDescription = faultDescription;
						this.currentCamper.currentMileage = currentMileage;
						this.currentCamper.totalMileage = totalMileage;
						this.currentCamper.batteryPercent = batteryPercent;
						this.currentCamper.speed = speed;
						this.currentCamper.batteryCapacity = batteryCapacity;
						// console.log('解析结果:', {
						// 	batteryPercent,
						// 	batteryCapacity,
						// 	speed,
						// 	currentMileage,
						// 	totalMileage,
						// 	modeA,
						// 	modeB
						// });
						// console.log("this.heartProblem:" + this.heartProblem);
						if (this.heartProblem === 1) {
							// 立即发送停止速度指令
							const command = 'FE54060B000B';
							this.sendCommand(command);
							this.heartProblem = 0;
						}


						// 更新当前连接的露营车
						const currentLYC = uni.getStorageSync('currentHotspot');
						let campers = uni.getStorageSync('campers') || [];

						campers = campers.map(camper => {
							if (camper.wifiName === currentLYC.wifiName) {
								return {
									...camper,
									batteryPercent,
									batteryCapacity,
									speed,
									currentMileage,
									totalMileage,
									modeA,
									modeB,
									brakeStatus,
									lightStatus
								};
							}
							return camper;
						});

						// this.camperList = campers;
						// uni.setStorageSync('campers', campers);

						// console.log('更新后的露营车信息:', campers);
					},
					fail: (err) => {
						console.log('心跳失败:', err);
						this.heartbeatFailCount = (this.heartbeatFailCount || 0) + 1;
						this.heartProblem = 1;
						this.heartStatus = 0;
						if (this.heartbeatFailCount >= 2) {
							this.currentConnectionStatus = 0;
							uni.setStorageSync('currentConnectionStatus', 0);
						}
						// this.setCamperDisconnected();
					}
				});
			},

			//获取授权
			async getPermission() {
				var result = await permision.requestAndroidPermission("android.permission.ACCESS_FINE_LOCATION")
				var strStatus
				if (result == 1) {
					strStatus = "已获得授权"
				} else if (result == 0) {
					strStatus = "未获得授权"
				} else {
					strStatus = "被永久拒绝权限"
				}
				uni.showModal({
					content: permisionID + strStatus,
					showCancel: false
				});
			},
			// 权限初始化
			init() {
				FvvUniWifiHelper.init(res => {
					console.log(res)
				})
				this.getPermission()
			},
			//获取局域网设备，来判断设备是否连接成功
			getLAN(callback) {
				const port = 80;
				FvvUniWifiHelper.getLAN(port, res => {
					console.log('局域网返回结果:', res.ip);
					if (res && res.ip) {
						callback(res.ip);
					} else {
						callback(null);
					}
				});
			},
			getLoadLAN() {
				console.log("获取初始ip");
				const port = 80;
				const requestId = ++this.getLANRequestId; // 记录本次调用的唯一标识
				let isResponded = false;

				const timeout = setTimeout(() => {
					if (!isResponded && requestId === this.getLANRequestId) {
						console.log('局域网设备连接超时，判定为失败');
						// this.currentConnectionStatus = 0;
						// uni.setStorageSync('currentConnectionStatus', 0);
					}
				}, 5000);

				FvvUniWifiHelper.getLAN(port, res => {
					if (res && res.ip && requestId === this.getLANRequestId) {
						isResponded = true;
						clearTimeout(timeout);
						console.log('局域网返回结果:', res.ip);
						uni.setStorageSync('currentIP', res.ip);
						// this.currentConnectionStatus = 1;
						// uni.setStorageSync('currentConnectionStatus', 1);
					}
				});
			},
			//断开
			setCamperDisconnected() {
				const current = uni.getStorageSync('currentHotspot');
				if (!current) return;

				const updatedCampers = this.camperList.map(camper => {
					if (camper.wifiName === current.wifiName) {
						return {
							...camper,
							wifiStatus: 0
						};
					}
					return camper;
				});
				this.camperList = updatedCampers;
				this.currentConnectionStatus = 0;
				uni.setStorageSync('currentConnectionStatus', 0); // ← 添加本地存储
				uni.setStorageSync('campers', updatedCampers);
				// uni.removeStorageSync('currentIP'); // 可选：移除旧 IP
			},
			// 获取当前ip
			getCurrentIP() {
				const ip = uni.getStorageSync('currentIP');
				// console.log('currentIP:', ip);
				return ip;
			},
			// 创建热点
			createHotspot() {
				this.showHotspot = false;
				this.selectedCamper = this.currentModel;
				if (this.selectedCamper) {
					// 是点击已有露营车，只展示热点，不创建新露营车
					this.selectedCamper = null;
					//创建热点
					this.createWifiByScan(this.wifiName, this.wifiPassword);
					// 存储当前正在创建的热点信息
					uni.setStorageSync('currentHotspot', {
						wifiName: this.wifiName,
						wifiPassword: this.wifiPassword
					});
					return;
				}

				// 将扫描二维码的露营车存本地
				// 提取所有已有编号
				const numbers = this.campers.map(camper => {
					const match = camper.name.match(/观猎(\d+)号/);
					return match ? parseInt(match[1], 10) : 0;
				});
				const maxNum = numbers.length ? Math.max(...numbers) : 0;
				const newIndex = maxNum + 1;

				const name = `观猎${newIndex}号`;
				// const model = this.wifiName.split('_')[1] || this.wifiName;
				const model = 'fe008';

				const wifiStatus = 0; // 默认wifi未连接

				this.campers.push({
					name,
					model,
					wifiStatus,
					wifiName: this.wifiName,
					wifiPassword: this.wifiPassword,
					// 默认状态字段
					modeA: 0, // 默认模式 1高速  2轻载 3巡航 4户外 5助力
					modeB: 0, // 默认模式 1高速  2轻载 3巡航 4户外 5助力
					brakeStatus: false, // 刹车状态（false=未刹车）
					lightStatus: false, // 灯光状态
					routerStatus: false, // 路由器状态
					hornStatus: false, // 喇叭状态
					autoFollowStatus: false, // 自动跟随状态
					oneKeyRecallStatus: false, // 一键召回状态

					// 默认数值
					batteryPercent: 0, // 电量百分比
					speed: 0, // 当前速度
					batteryCapacity: 0, // 电池容量（单位根据需求，如mAh）
					currentMileage: 0, // 当前里程
					totalMileage: 0 // 总里程
				});
				uni.setStorageSync('campers', this.campers);
				console.log('更新后的露营车信息:', this.campers);
				//创建热点
				this.createWifiByScan(this.wifiName, this.wifiPassword);
				// 存储当前正在创建的热点信息
				uni.setStorageSync('currentHotspot', {
					wifiName: this.wifiName,
					wifiPassword: this.wifiPassword
				});
			},
			//创建热点
			createWifiByScan(ssid, password) {
				getApp().globalData.shouldSendHeartbeat = true; //点击创建热点，开始发送心跳
				this.init();
				this.isConnecting = true; // 显示加载状态
				console.log("创建wifi");
				console.log(this.shouldCheckWifi);

				FvvUniWifiHelper.createWifi({
					name: ssid,
					password: password
				}, res => {
					console.log('创建热点结果:', res);
					// 设置标志位，在 onShow 时触发倒计时检测
					this.shouldCheckWifi = true;
				});
			},
			//设备是否连接检测
			startWifiCheck() {
				// 防止重复定时器
				if (this.checkIntervalId) clearInterval(this.checkIntervalId);
				if (this.timeoutId) clearTimeout(this.timeoutId);
				if (this.heartbeatIntervalId) clearInterval(this.heartbeatIntervalId);
				if (this.heartbeatTimeoutId) clearTimeout(this.heartbeatTimeoutId);

				let checkCount = 0;
				const maxChecks = 10;
				const intervalTime = 2000;
				console.log("开始局域网扫描...");

				this.checkIntervalId = setInterval(() => {
					this.getLAN(ip => {
						if (ip) {
							clearInterval(this.checkIntervalId);
							clearTimeout(this.timeoutId);
							console.log('IP检测成功:', ip);

							// 开始心跳检测
							this.startHeartbeatCheck(ip);
						}
					});

					checkCount++;
					if (checkCount >= maxChecks) {
						clearInterval(this.checkIntervalId);
						this.isConnecting = false;
						this.shouldCheckWifi = false;
						console.log('IP检测超时');
						this.currentConnectionStatus = 0;
						uni.setStorageSync('currentConnectionStatus', 0);
						uni.showToast({
							title: '连接超时，请稍后再试',
							icon: 'none',
							duration: 2000
						});
					}
				}, intervalTime);

				this.timeoutId = setTimeout(() => {
					clearInterval(this.checkIntervalId);
					this.isConnecting = false;
					this.shouldCheckWifi = false;
					console.log('IP检测总超时');
					this.currentConnectionStatus = 0;
					uni.setStorageSync('currentConnectionStatus', 0);
					uni.showToast({
						title: '设备未连接，请重试',
						icon: 'none',
						duration: 2000
					});
				}, maxChecks * intervalTime);
			},
			startHeartbeatCheck(ip) {
				if (this.heartbeatInProgress) {
				  console.log('心跳检测已在进行，忽略本次启动');
				  return;
				}
				this.heartbeatInProgress = true;
				let heartbeatCount = 0;
				const maxHeartbeatChecks = 100; // 最多检测50次
				const heartbeatInterval = 100; // 每100ms检测一次

				let hasConnected = false; // <-- 新增标志

				console.log('开始心跳检测...');

				this.heartbeatIntervalId = setInterval(() => {
					if (hasConnected) return; // 已成功就直接不跑
					uni.request({
						url: `http://${ip}/heartbeat`,
						method: 'GET',
						timeout: 3000,
						success: (res) => {
							if (hasConnected) return; // <-- 防止多次处理
							hasConnected = true; // 第一时间锁住
							console.log('心跳响应:', res);

							const hexStr = res.data?.toUpperCase?.().replace(/\s+/g, '');
							if (!hexStr || !hexStr.startsWith('FE55')) {
								console.warn('心跳数据格式不正确');
								return;
							}

							const body = hexStr.slice(8);
							if (body.length < 26) {
								console.warn('心跳数据长度不足');
								return;
							}

							// 心跳确认成功
							hasConnected = true; // 标记已连接
							console.log('心跳有效，连接完成！');
							clearInterval(this.heartbeatIntervalId);
							clearTimeout(this.heartbeatTimeoutId);
							this.isConnecting = false;
							this.shouldCheckWifi = false;
							

							// 更新露营车状态
							const camperIndex = this.camperList.findIndex(c => c.model === this
								.currentModel);
							if (camperIndex !== -1) {
								this.camperList[camperIndex].wifiStatus = 1;
								uni.setStorageSync('campers', this.camperList);
								console.log('露营车信息已更新:', this.camperList);
							}

							uni.setStorageSync('currentIP', ip);
							this.currentConnectionStatus = 1;
							uni.setStorageSync('currentConnectionStatus', 1);

							uni.showToast({
								title: '设备连接成功',
								icon: 'success',
								duration: 1500
							});
						},
						fail: (err) => {
							console.warn('心跳请求失败:', err);
						}
					});

					heartbeatCount++;
					if (heartbeatCount >= maxHeartbeatChecks) {
						if (hasConnected) return; // ✅ 已连接，完全退出
						clearInterval(this.heartbeatIntervalId);
						this.isConnecting = false;
						this.shouldCheckWifi = false;
						console.log('心跳检测超时');
						this.currentConnectionStatus = 0;
						uni.setStorageSync('currentConnectionStatus', 0);
						uni.showToast({
							title: '心跳超时，请重试',
							icon: 'none',
							duration: 2000
						});
					}
				}, heartbeatInterval);

				this.heartbeatTimeoutId = setTimeout(() => {
					if (hasConnected) return; // 超时前如果已成功，跳过
					clearInterval(this.heartbeatIntervalId);
					this.isConnecting = false;
					this.shouldCheckWifi = false;
					console.log('心跳检测总超时');
					this.currentConnectionStatus = 0;
					uni.setStorageSync('currentConnectionStatus', 0);
					uni.showToast({
						title: '设备连接超时，请重试',
						icon: 'none',
						duration: 2000
					});
				}, maxHeartbeatChecks * heartbeatInterval);
			},


			// startWifiCheck() {
			// 	// 防止重复定时器
			// 	if (this.checkIntervalId) clearInterval(this.checkIntervalId);
			// 	if (this.timeoutId) clearTimeout(this.timeoutId);
			// 	let checkCount = 0;
			// 	const maxChecks = 10;
			// 	const intervalTime = 2000;
			// 	console.log("获取局域网")
			// 	this.checkIntervalId = setInterval(() => {
			// 		this.getLAN(ip => {
			// 			if (ip) {
			// 				clearInterval(this.checkIntervalId);
			// 				clearTimeout(this.timeoutId);
			// 				this.isConnecting = false;
			// 				this.shouldCheckWifi = false;
			// 				console.log('设备已连接:', ip);
			// 				this.currentConnectionStatus = 1;
			// 				uni.setStorageSync('currentConnectionStatus', 1); // ← 添加本地存储
			// 				// 更新当前露营车的 wifiStatus 为 1
			// 				const camperIndex = this.camperList.findIndex(c => c.model === this
			// 					.currentModel);
			// 				if (camperIndex !== -1) {
			// 					this.camperList[camperIndex].wifiStatus = 1;
			// 					uni.setStorageSync('campers', this.camperList);
			// 					console.log('更新后的露营车信息:', this.camperList);
			// 				}
			// 				uni.setStorageSync('currentIP', ip);
			// 			}
			// 		});
			// 		checkCount++;
			// 		if (checkCount >= maxChecks) {
			// 			clearInterval(this.checkIntervalId);
			// 			this.isConnecting = false;
			// 			this.shouldCheckWifi = false;
			// 			console.log('连接超时');
			// 			this.currentConnectionStatus = 0;
			// 			uni.setStorageSync('currentConnectionStatus', 0); // ← 添加本地存储
			// 			// 超时弹窗提示
			// 			uni.showToast({
			// 				title: '连接超时，请稍后再试',
			// 				icon: 'none',
			// 				duration: 2000
			// 			});
			// 		}
			// 	}, intervalTime);

			// 	this.timeoutId = setTimeout(() => {
			// 		clearInterval(this.checkIntervalId);
			// 		this.isConnecting = false;
			// 		this.shouldCheckWifi = false;
			// 		console.log('10秒超时处理');
			// 		this.currentConnectionStatus = 0;
			// 		uni.setStorageSync('currentConnectionStatus', 0); // ← 添加本地存储
			// 		uni.showToast({
			// 			title: '设备未连接，请重试',
			// 			icon: 'none',
			// 			duration: 2000
			// 		});
			// 	}, maxChecks * intervalTime);
			// },
			confirmWifiConfig() {
				if (!this.wifiName || !this.wifiPassword) {
					uni.showToast({
						title: '请填写WiFi名称和密码',
						icon: 'none'
					});
					return;
				}

				// 判断 WiFi 名称是否与其他露营车重复（排除当前camper）
				const isDuplicate = this.camperList.some(camper =>
					camper.wifiName === this.wifiName && camper.wifiName !== this.currentCamper.wifiName
				);
				if (isDuplicate) {
					uni.showToast({
						title: 'WiFi名称已被其他露营车使用',
						icon: 'none'
					});
					return;
				}

				// === 生成协议命令 ===
				const nameHex = this.stringToHex(this.wifiName);
				const passwordHex = this.stringToHex(this.wifiPassword);
				const separator = '0A';
				// const contentHex = nameHex + separator + passwordHex;
				const contentHex = '08' + nameHex + separator + passwordHex;
				const contentLength = contentHex.length / 2;
				const totalLength = 2 + 1 + contentLength + 1;
				const lengthHex = totalLength.toString(16).padStart(2, '0').toUpperCase();
				const checksum = this.calculateChecksum(contentHex);
				const command = 'FE54' + lengthHex + contentHex + checksum;
				// console.log('生成的WiFi配置命令:', command);
				if (command === 'FE5409060000000006') {
					return;
				}
				// === 发送命令并关闭弹窗 ===
				this.sendCommand(command)
					.then(() => {
						// 同步状态用于视图更新
						// this.currentCamper.hornStatus = pressing;
						uni.showToast({
							title: '路由器设置成功',
							icon: 'success',
							duration: 2000
						});
					})
					.catch(() => {
						uni.showToast({
							title: '路由器设置失败',
							icon: 'none'
						});
					});

				// === 更新当前露营车信息并保存到本地 ===
				this.currentCamper.wifiName = this.wifiName;
				this.currentCamper.wifiPassword = this.wifiPassword;

				// 替换 camperList 中对应的项
				const index = this.camperList.findIndex(item => item.wifiName === this.currentModel);
				if (index !== -1) {
					this.camperList[index] = {
						...this.currentCamper
					};
				}

				// 存储更新后的数据
				uni.setStorageSync('camperList', this.camperList);
				uni.setStorageSync('currentCamper', this.currentCamper);
				this.showLYQspot = false;
			},

			stringToHex(str) {
				return Array.from(str).map(c => c.charCodeAt(0).toString(16).padStart(2, '0')).join('').toUpperCase();
			},

			calculateChecksum(hexStr) {
				let sum = 0;
				for (let i = 0; i < hexStr.length; i += 2) {
					sum += parseInt(hexStr.substr(i, 2), 16);
				}
				// 只取低8位
				return (sum % 256).toString(16).padStart(2, '0').toUpperCase();
			},
			//动态图标设置
			getIcon(name, active) {
				return `/static/${name}${active ? '1' : ''}.png`; // 兼容 App、H5、小程序
			},
			hexStringToFloat(hexString) {
				// 去除所有非十六进制字符（如空格等）
				hexString = hexString.replace(/[^0-9A-Fa-f]/g, '');

				// 将十六进制字符串转换为字节数组
				const bytes = [];
				for (let i = 0; i < hexString.length; i += 2) {
					bytes.push(parseInt(hexString.substr(i, 2), 16));
				}

				// 使用 DataView 解析字节数组为浮点数
				const buffer = new ArrayBuffer(4); // 假设是32位浮点数
				const view = new DataView(buffer);

				// 将字节数组写入 DataView
				for (let i = 0; i < bytes.length; i++) {
					view.setUint8(i, bytes[i]);
				}

				// 读取浮点数
				return view.getFloat32(0, true); // 假设是小端字节序
			},
			/**
			 * 发送指令并自动重试
			 * @param {string} commandHex 指令
			 * @param {number} maxRetries 最大尝试次数
			 * @param {number} delayBetweenRetries 每次失败后等待的毫秒数
			 */
			sendCommandWithRetry(commandHex, maxRetries = 10, delayBetweenRetries = 300) {
				let attempt = 0;

				const trySend = () => {
					attempt++;
					console.log(`第${attempt}次发送归位指令`);

					this.sendCommand(commandHex)
						.then(res => {
							console.log('归位指令发送成功:', res);
							// uni.showToast({
							// 	title: `归位指令发送成功`,
							// 	icon: 'none',
							// 	duration: 1000
							// });
							// 成功就不再重试
						})
						.catch(err => {
							// uni.showToast({
							// 	title: `归位失败，第${attempt}次重试`,
							// 	icon: 'none',
							// 	duration: 1000
							// });
							console.warn('归位指令发送失败:', err);
							if (attempt < maxRetries) {
								setTimeout(() => {
									trySend();
								}, delayBetweenRetries);
							} else {
								console.error(`归位指令连续${maxRetries}次失败，已放弃重试`);
							}
						});
				};

				// 第一次尝试
				trySend();
			},
			// 发送指令命令
			sendCommand(commandHex) {
				console.log("指令：" + commandHex);
				this.resetCountdown();
				const currentIP = this.getCurrentIP();
				if (!currentIP) {
					// this.setCamperDisconnected();
					return Promise.reject('设备未连接');
				}
				if (this.currentConnectionStatus === 0) {
					return Promise.reject('WiFi未连接');
				}
				const rssi = uni.getStorageSync('camperRSSI') || 0;
				if (rssi == 3) {
					return Promise.reject('信号较弱，请靠近露营车后重试');

				}
				return new Promise((resolve, reject) => {
					uni.request({
						url: `http://${currentIP}/command`,
						method: 'POST',
						data: commandHex,
						timeout: 3000,
						success: (res) => {
							console.log('命令发送成功:', res);
							resolve(res);
						},
						fail: (err) => {
							console.log('命令发送失败:', err);
							// this.setCamperDisconnected();
							reject(err);
						}
					});
				});
			},

		}
	};
</script>

<style scoped>
	.ctrl-btn {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
	}

	.ctrl-icon {
		width: 115rpx;
		height: 115rpx;
		padding-bottom: 20rpx;
		padding-top: 20rpx;
	}

	text {
		font-size: 28rpx;
	}

	.container {
		padding: 80rpx 30rpx 30rpx 30rpx;
		padding-bottom: 160rpx;
		background: #f5f7fa;
		min-height: 80vh;
		overflow: auto;
		touch-action: none;
		/* 禁止页面拖动 */
	}

	.header {
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.logo {
		width: 290rpx;
		height: 76rpx;
	}

	.distance-info {
		margin-top: 10rpx;
		color: #333;
		font-size: 26rpx;
		line-height: 40rpx;
		/* 增加行高让上下有呼吸感 */
	}

	.highlight {
		color: #0052d9;
		font-weight: bold;
		margin: 0 8rpx;
	}

	.model {
		font-size: 26rpx;
	}

	.model-wrap {
		display: flex;
		align-items: center;
	}

	.model {
		font-size: 26rpx;
		color: #333;
		margin-right: 10rpx;
	}

	.model-icon {
		width: 28rpx;
		height: 14rpx;
	}

	.wifi {
		background: #D0DCFC;
		color: #0052d9;
		border-radius: 30rpx;
		padding: 10rpx 20rpx;
		font-size: 24rpx;
		margin-top: 10rpx;
		display: flex;
		/* 横向排列图标和文字 */
		align-items: center;
		/* 垂直居中 */
	}

	.wifi-icon {
		width: 29rpx;
		/* 你可以根据需要调节大小 */
		height: 20rpx;
		margin-right: 10rpx;
		/* 图标和文字间距 */
	}


	/* 状态卡片 */
	.status-card {
		background: #fff;
		border-radius: 20rpx;
		margin-top: 30rpx;
		padding: 30rpx;
		box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.05);
		display: flex;
		/* Set flex layout */
		align-items: center;
		/* Vertically align items */
		justify-content: space-between;
		/* Distribute space between items */
	}

	.cart-img {
		width: 141rpx;
		height: 164rpx;
	}

	.status-row {
		display: flex;
		justify-content: space-between;
		flex: 1;
	}

	.status-item {
		display: flex;
		flex-direction: column;
		/* 关键：垂直排列图标和文字 */
		align-items: center;
		/* 居中对齐图标和文字 */
		flex: 1;
	}

	.icon {
		width: 90rpx;
		height: 96rpx;
		margin-bottom: 10rpx;
		/* 图文间距 */
	}


	.green {
		color: #00aa00;
	}

	.red {
		color: red;
	}




	/* 控制按钮 */
	.control-section {
		margin-top: 10rpx;
	}

	.row-top {
		display: flex;
		justify-content: space-between;
		flex-wrap: wrap;
		margin-bottom: 20rpx;
		border: 1px solid #ccc;
		/* 添加边框，颜色为浅灰色 */
		border-radius: 8px;
		/* 添加圆角效果 */
		padding: 10px;
		/* 添加内边距，可根据需要调整 */
		background-color: #f9f9f9;
		/* 可选：添加背景颜色 */
	}

	.ctrl-btn {
		width: 18%;
		align-items: center;
		text-align: center;
	}

	.ctrl-icon {
		width: 115rpx;
		height: 115rpx;
		margin-bottom: 5rpx;
	}

	.right-info {
		margin-top: 45rpx;
		/* 根据需要调整，如 10~20rpx */
	}

	.row-bottom {
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.side-column {
		display: flex;
		flex-direction: column;
		justify-content: space-between;
		/* height: 320rpx; */
		border: 1px solid #ccc;
		/* 添加边框，颜色为浅灰色 */
		border-radius: 8px;
		/* 添加圆角效果 */
		padding: 10px;
		/* 添加内边距，可根据需要调整 */
		background-color: #f9f9f9;
		/* 可选：添加背景颜色 */
		/* margin-bottom: 10px; */
		/* 添加外边距，可根据需要调整 */


	}

	.ctrl-btn.small {
		width: 115rpx;
	}



	/* 确保居中样式 */
	/* 最外层灰色圆环包裹层 */
	.joystick-ring {
		width: 340rpx;
		/* 比容器大40rpx (即 padding 20) */
		height: 340rpx;
		padding: 1rpx;
		border-radius: 50%;
		background: #E9E9E9;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.joystick-container {
		width: 300rpx;
		height: 300rpx;
		position: relative;
	}

	.joystick-track {
		width: 100%;
		height: 100%;
		border-radius: 50%;
		background: #fff;
		box-shadow: 0 0 12rpx rgba(0, 0, 0, 0.05);
		position: relative;
		overflow: hidden;
	}

	.joystick-thumb {
		width: 80rpx;
		height: 80rpx;
		background: #0052d9;
		border-radius: 50%;
		position: absolute;
		left: 50%;
		top: 50%;
		transform: translate(-50%, -50%);
		/* 默认居中 */
		transition: transform 0.1s;
	}


	.bottom-row-box {
		margin-top: 10rpx;
		display: flex;
		justify-content: space-around;
		align-items: center;
	}

	.bottom-btn {
		/* margin: 2px 2px 2px 5px; */
		background: #ffffff;
		width: 436rpx;
		height: 153rpx;
		border-radius: 30rpx;
		display: flex;
		align-items: center;
		/* Vertically center the image and text */
		justify-content: center;
		/* Horizontally center the content inside the button */
	}

	.bottom-btn .ctrl-icon {
		width: 115rpx;
		/* Icon size */
		height: 115rpx;
		margin-right: 20rpx;
		/* Space between the image and text */
	}

	.bottom-btn text {
		font-size: 28rpx;
		text-align: left;
		/* Align the text to the left */
	}




	/* 故障代码 */
	.error-code {
		background: #fff;
		padding: 20rpx;
		border-radius: 20rpx;
		margin-top: 10rpx;
		font-size: 26rpx;
	}

	/* 底部导航 */
	.tabbar {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		height: 120rpx;
		background: #ffffff;
		display: flex;
		justify-content: space-around;
		align-items: center;
		box-shadow: 0 -4rpx 10rpx rgba(0, 0, 0, 0.05);
	}

	.tab-item {
		display: flex;
		flex-direction: column;
		align-items: center;
		color: #999;
		font-size: 26rpx;
	}

	.tab-item.active {
		color: #000;
	}

	.icon-tab {
		width: 48rpx;
		height: 48rpx;
		margin-bottom: 4rpx;
	}

	.modal {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0.6);
		display: flex;
		justify-content: center;
		align-items: center;
		z-index: 1000;
	}

	.modal-content {
		width: 600rpx;
		background: #fff;
		border-radius: 20rpx;
		padding: 40rpx;
		box-sizing: border-box;
	}

	.modal-title {
		font-size: 36rpx;
		font-weight: bold;
		text-align: center;
		margin-bottom: 30rpx;
	}

	.modal-tip {
		font-size: 24rpx;
		color: #666;
		margin-top: 20rpx;
	}

	.modal-buttons {
		display: flex;
		justify-content: space-between;
		margin-top: 30rpx;
	}

	.info-box {
		margin-top: 10rpx;
		background: #f5f5f5;
		padding: 20rpx;
		border-radius: 12rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
	}

	.copy-icon {
		width: 40rpx;
		height: 40rpx;
	}

	.loading-overlay {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: rgba(0, 0, 0, 0.5);
		z-index: 999;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.loading-box {
		display: flex;
		flex-direction: column;
		align-items: center;
		color: white;
	}

	.spinner {
		width: 60rpx;
		height: 60rpx;
		border: 6rpx solid #fff;
		border-top: 6rpx solid transparent;
		border-radius: 50%;
		animation: spin 1s linear infinite;
	}

	@keyframes spin {
		from {
			transform: rotate(0deg);
		}

		to {
			transform: rotate(360deg);
		}
	}

	.loading-text {
		margin-top: 20rpx;
		font-size: 28rpx;
	}

	.idle-shutdown-tip {
		font-size: 24rpx;
		color: #999;
		margin-top: 12rpx;
		line-height: 36rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
	}


	.countdown {
		color: #ff4d4f;
		font-weight: bold;
	}

	.tip-left {
		flex: 1;
	}

	.tip-right {
		white-space: nowrap;
		margin-left: 20rpx;
	}

	.divider-line {
		height: 1px;
		background-color: #eee;
		margin: 12rpx 0;
	}

	.left {
		margin-right: 10px;
	}

	.rssi {
		font-size: 28rpx;
		color: #999;
		margin-top: 4rpx;
	}


	/* 	.mode-group {
	  display: flex;
	  align-items: center;
	  border: 1rpx solid #ddd;
	  border-radius: 16rpx;
	  background-color: #f9f9f9;
	  padding: 10rpx;
	}
	
	.mode-subgroup {
	  display: flex;
	} */

	/* 中间分隔线 */
	/* .mode-divider {
	  width: 1rpx;
	  height: 150rpx;
	  background-color: #ddd;
	  margin: 0 10rpx;
	} */
</style>